<template>
	<div
		ref="rootRef"
		:class="classes()"
		:style="style()"
	>{{showContent()}}</div>
</template>

<script setup lang="ts">
import type {EllipsisType} from './type';
import {
	shallowRef,
	watchEffect,
	onMounted,
	onUpdated,
} from 'vue';
import {operateDom} from '../../../util';
/**
 * 文字省略组件
 * @author 唐国雄
 * @date 2022/10/12
 * 属性----------------------
 * :content				内容
 * :rows				最大行数
 * :disabled			禁用状态
 * 事件----------------------
 * @overflow			是否溢出
 * 方法----------------------
 * jsOverflowFn()		重新计算溢出(兼容ie)
 * checkOverflow()		检测溢出状态是否变化(发出事件)
 */
if(typeof cache==='function'){
	cache=cache();
}
const {lineClampSupport,ele}=cache;

const emit=defineEmits<{
	(e:'overflow',overflow:boolean):void;
}>();
const props=withDefaults(defineProps<{
	content:string;
	rows?:number;
	disabled?:boolean;
}>(),{
	rows:1,
});
const rootRef=shallowRef<HTMLElement>(null);
const jsContent=shallowRef<string>('');
//region 实现方式
const type=(():EllipsisType => {
	if(props.rows<=1){
		return 'cssTextOverflow';
	}else if(lineClampSupport){
		return 'cssLineClamp';
	}
	return 'js';
});
//endregion
//region 类名
const classes=(() => {
	let classes='pf-Ellipsis';
	if(!props.disabled){
		classes+=` pf--type-${type()} pf--enable`;
	}
	return classes;
});
//endregion
//region 样式
const style=(() => {
	if(type()==='cssLineClamp'&&!props.disabled){
		return {
			'-webkit-line-clamp':props.rows,
		};
	}
	return null;
});
//endregion
//region 实际显示内容
const showContent=(() => {
	if(type()==='js'&&!props.disabled){
		return jsContent.value;
	}
	return props.content;
});
//endregion
//region 检测溢出
let oldOverflow;
const checkOverflow=operateDom(():void => {
	let overflow:boolean;
	const typeVal=type();
	if(props.disabled){
		overflow=false;
	}else{
		if(typeVal==='cssTextOverflow'){
			const {offsetWidth,scrollWidth}=rootRef.value;
			overflow=scrollWidth>offsetWidth;
		}else if(typeVal==='cssLineClamp'){
			const {offsetHeight,scrollHeight}=rootRef.value;
			overflow=scrollHeight>offsetHeight;
		}else{
			overflow=jsContent.value!==props.content;
		}
	}
	if(oldOverflow!==overflow){
		oldOverflow=overflow;
		emit('overflow',overflow);
	}
});
//endregion
//region js计算溢出
const jsOverflowFn=(():void => {
	if(type()!=='js'){
		return;
	}
	const content=props.content;
	rootRef.value.appendChild(ele);
	ele.textContent=content;
	const maxHeight=props.rows*Number.parseFloat(getComputedStyle(ele).lineHeight);
	const findPos=(start,end) => {
		if(start+1===end){
			jsContent.value=content.slice(0,start)+'...';
			return;
		}
		const mid=Math.ceil((start+end)/2);
		ele.textContent=content.slice(0,mid)+'...';
		if(ele.offsetHeight>maxHeight){
			findPos(start,mid);
		}else{
			findPos(mid,end);
		}
	};
	if(ele.offsetHeight>maxHeight){
		findPos(0,content.length);
	}else{
		jsContent.value=content;
	}
});
//endregion
onMounted(() => {
	if(!lineClampSupport){
		watchEffect(jsOverflowFn);
	}
	checkOverflow();
});
onUpdated(checkOverflow);
//region 导出的内容
defineExpose({
	jsOverflowFn,
	checkOverflow,
});
//endregion
</script>

<script lang="ts">
//region 类型声明
interface Cache{
	lineClampSupport:boolean;
	ele:HTMLElement;
}
//endregion
//region 全局缓存
let cache:Cache|(() => Cache)=function(){
	const lineClampSupport='-webkit-line-clamp' in document.body.style;
	let ele;
	if(!lineClampSupport){
		ele=document.createElement('div');
		ele.className='pf-Ellipsis_measure';
	}
	return {
		lineClampSupport,
		ele,
	};
};
//endregion
export default {};
</script>